#include "FabricaBonus.h"

#include "BonusModel.h"

#include "BonusCambioMultiplicador.h"
#include "BonusCambioDePresa.h"
#include "BonusPuntajeAlContrario.h"
#include "BonusCongelar.h"
#include "BonusDuplicadorVelocidad.h"
#include "BonusReducirVelocidadOponente.h"

#include "TexturasBonus.h"
//#include "Punto.h"
#include "IteradorLista.h"

#include "EscenarioModelo.h"

#include "Logger.h"
#include <sstream>

bool FabricaBonus::instance = false;
FabricaBonus* FabricaBonus::singleton = 0 ;
// Tipo de bonus que permite invertir roles entre personajes
std::string FabricaBonus::ID_CARNIVORO = "carnivoro" ;

std::string FabricaBonus::ID_CONGELAR = "congelar" ;
std::string FabricaBonus::ID_DUPLICA = "duplicar" ;
std::string FabricaBonus::ID_CAMBIO_PRESA = "fantasma" ;
std::string FabricaBonus::ID_PTO_OPONENTE = "puntos" ;
std::string FabricaBonus::ID_RAPIDO = "rapido" ;
std::string FabricaBonus::ID_LENTO = "lento" ;

void FabricaBonus::inicializar(){

	listaPropiedades = new Lista<PropiedadesFabricaBonus> ;

	PropiedadesFabricaBonus *duplicaPto, *cambioPresa, *ptoOponente, *congelar ;
	PropiedadesFabricaBonus *rapido, *lento ;
	//ESTO LO AGREGO POR SI PUEDO SETEAR DESDE ACA EN VEZ DE EL XML
	//las seteos de los elementos de los 3 array aparecen en este orden:
	//{duplicaPto,cambioPresa,ptoOponente,congelar,rapido,lento}
	//por ejemplo, los primeros valores para los tres array son para el bonus que duplica puntos.
	int cant[] = {0,0,0,0,0,2};
	int prob[] = {0,0,0,0,0,100};
	int dura[] = {0,0,0,0,10};

	duplicaPto = new PropiedadesFabricaBonus(FabricaBonus::ID_DUPLICA);
	duplicaPto->setCantidad(cant[0]);
	duplicaPto->setProbabilidad(prob[0]);
	duplicaPto->setDuracion(dura[0]);
	duplicaPto->setTextura(new Textura("BONUS DUPLICA PUNTOS", "img/default.bmp" ,0,0,0,0,"#FFFFFF",0,0));

	cambioPresa = new PropiedadesFabricaBonus(FabricaBonus::ID_CAMBIO_PRESA);
	cambioPresa->setCantidad(cant[1]);
	cambioPresa->setProbabilidad(prob[1]);
	cambioPresa->setDuracion(dura[1]);
	cambioPresa->setTextura(new Textura("BONUS CAMBIO PRESA", "img/default.bmp" ,0,0,0,0,"#FFFFFF",0,0));

	ptoOponente = new PropiedadesFabricaBonus(FabricaBonus::ID_PTO_OPONENTE);
	ptoOponente->setCantidad(cant[2]);
	ptoOponente->setProbabilidad(prob[2]);
	ptoOponente->setDuracion(dura[2]);
	ptoOponente->setTextura(new Textura("BONUS PTO OPONENTE", "img/default.bmp" ,0,0,0,0,"#FFFFFF",0,0));

	congelar = new PropiedadesFabricaBonus(FabricaBonus::ID_CONGELAR);
	congelar->setCantidad(cant[3]);
	congelar->setProbabilidad(prob[3]);
	congelar->setDuracion(dura[3]);
	congelar->setTextura(new Textura("BONUS HIELO", "img/default.bmp" ,0,0,0,0,"#FFFFFF",0,0));
	
	rapido = new PropiedadesFabricaBonus(FabricaBonus::ID_RAPIDO);
	rapido->setCantidad(cant[4]);
	rapido->setProbabilidad(prob[4]);
	rapido->setDuracion(dura[4]);
	rapido->setTextura(new Textura("BONUS VELOCIDAD RAPIDO", "img/default.bmp" ,0,0,0,0,"#FFFFFF",0,0));

	lento = new PropiedadesFabricaBonus(FabricaBonus::ID_LENTO);
	lento->setCantidad(cant[5]);
	lento->setProbabilidad(prob[5]);
	lento->setDuracion(dura[5]);
	lento->setTextura(new Textura("BONUS VELOCIDAD LENTO", "img/default.bmp" ,0,0,0,0,"#FFFFFF",0,0));

	listaPropiedades->agregar(duplicaPto);
	listaPropiedades->agregar(cambioPresa);
	listaPropiedades->agregar(ptoOponente);
	listaPropiedades->agregar(congelar);
	listaPropiedades->agregar(rapido);
	listaPropiedades->agregar(lento);

	this->sorteo = 0;
	this->sorteoCargado = false ;
}

// Busca en la lista las propiedades de ese ID
PropiedadesFabricaBonus* FabricaBonus::getPropiedades(const string& id){
	IteradorLista<PropiedadesFabricaBonus>* itProps = new IteradorLista<PropiedadesFabricaBonus>(this->listaPropiedades);
	PropiedadesFabricaBonus* actual = 0;
	PropiedadesFabricaBonus* res = 0;
	while(itProps->tieneSiguiente()){
		actual = itProps->siguiente();
		if(actual->getId() == id ){
			res = actual ;
			break;
		}
	}
	return res;

}

Lista<PropiedadesFabricaBonus>* FabricaBonus::getListaPropiedades(){
	return this->listaPropiedades;
}

//los enumero segun como estan ordenados en el enunciado
//1ro bonus especial
PersonajeBonus* FabricaBonus::getBonusDuplicaMisPuntosAcumulados(){
	PersonajeBonus* pBonus = 0 ;
	PropiedadesFabricaBonus* props = this->getPropiedades(FabricaBonus::ID_DUPLICA);

	if(props->getCantidad() > 0){
		props->decrementarCantidad();

		Punto* dummy = new Punto(0,0);
		BonusModel* bm = new BonusCambioMultiplicador(dummy,0,true,2);
		bm->setDuracionEfecto(props->getDuracion()*1000);
		bm->setProbabilidad(props->getProbabilidad());
		bm->setCantidad(props->getCantidad());

		TexturasBonus* tBonus = new TexturasBonus(props->getTextura());
		pBonus = new PersonajeBonus(tBonus,bm,"DOBLE-CEREZA");
	}

	return pBonus;
}

//2to bonus especial
PersonajeBonus* FabricaBonus::getBonusCambioDePresa(){
	PersonajeBonus* pBonus = 0 ;
	PropiedadesFabricaBonus* props = this->getPropiedades(FabricaBonus::ID_CAMBIO_PRESA);

	if(props->getCantidad() > 0){
		props->decrementarCantidad();

		Punto* dummy = new Punto(0,0);
		BonusModel* bm = new BonusCambioDePresa(dummy,0,true);
		bm->setDuracionEfecto(props->getDuracion()*1000);
		bm->setProbabilidad(props->getProbabilidad());
		bm->setCantidad(props->getCantidad());

		TexturasBonus* tBonus = new TexturasBonus(props->getTextura());
		pBonus = new PersonajeBonus(tBonus,bm,"BOTON");
	}

	return pBonus;

}

//3er bonus especial
PersonajeBonus* FabricaBonus::getBonusAdquirirPuntosDelOponente(){
	PersonajeBonus* pBonus = 0 ;
	PropiedadesFabricaBonus* props = this->getPropiedades(FabricaBonus::ID_PTO_OPONENTE);

	if(props->getCantidad() > 0){
		props->decrementarCantidad();

		Punto* dummy = new Punto(0,0);
		BonusModel* bm = new BonusPuntajeAlContrario(dummy,0,true);
		bm->setDuracionEfecto(props->getDuracion()*1000);
		bm->setProbabilidad(props->getProbabilidad());
		bm->setCantidad(props->getCantidad());

		TexturasBonus* tBonus = new TexturasBonus(props->getTextura());
		pBonus = new PersonajeBonus(tBonus,bm,"PACMEN");
	}

	return pBonus;

}
//4to bonus especial
PersonajeBonus* FabricaBonus::getBonusCongelar(){
	PersonajeBonus* pBonus = 0 ;
	PropiedadesFabricaBonus* props = this->getPropiedades(FabricaBonus::ID_CONGELAR);

	if(props->getCantidad() > 0){
		props->decrementarCantidad();

		Punto* dummy = new Punto(0,0);
		BonusModel* bm = new BonusCongelar(dummy,0,true);
		bm->setDuracionEfecto(props->getDuracion()*1000);
		bm->setProbabilidad(props->getProbabilidad());
		bm->setCantidad(props->getCantidad());
		
		TexturasBonus* tBonus = new TexturasBonus(props->getTextura());
		pBonus = new PersonajeBonus(tBonus,bm,"HIELO");

	}
	return pBonus ;

}


//5to bonus especial
PersonajeBonus* FabricaBonus::getBonusDuplicarVelocidad(){
	PersonajeBonus* pBonus = 0 ;
	PropiedadesFabricaBonus* props = this->getPropiedades(FabricaBonus::ID_RAPIDO);

	if(props->getCantidad() > 0){
		props->decrementarCantidad();

		Punto* dummy = new Punto(0,0);
		BonusModel* bm = new BonusDuplicadorVelocidad(dummy,0,true);
		bm->setDuracionEfecto(props->getDuracion()*1000);
		bm->setProbabilidad(props->getProbabilidad());
		bm->setCantidad(props->getCantidad());

		TexturasBonus* tBonus = new TexturasBonus(props->getTextura());
		pBonus = new PersonajeBonus(tBonus,bm,"RAYO");
	}

	return pBonus;

}

//6to bonus especial
PersonajeBonus* FabricaBonus::getBonusReducirVelocidadOponente(){
	PersonajeBonus* pBonus = 0 ;
	PropiedadesFabricaBonus* props = this->getPropiedades(FabricaBonus::ID_LENTO);

	if(props->getCantidad() > 0){
		props->decrementarCantidad();
		Punto* dummy = new Punto(0,0);
		BonusModel* bm = new BonusReducirVelocidadOponente(dummy,0,true);
		bm->setDuracionEfecto(props->getDuracion()*1000);
		bm->setProbabilidad(props->getProbabilidad());
		bm->setCantidad(props->getCantidad());

		TexturasBonus* tBonus = new TexturasBonus(props->getTextura());
		pBonus = new PersonajeBonus(tBonus,bm,"SUENIO");
	}

	return pBonus;

}

FabricaBonus::FabricaBonus(){
	this->inicializar();
}

FabricaBonus* FabricaBonus::getInstance(){
	if(!FabricaBonus::instance){
		FabricaBonus::singleton = new FabricaBonus();
		FabricaBonus::instance = true;
	}
	return FabricaBonus::singleton;
}

FabricaBonus::~FabricaBonus(){
	delete this->listaPropiedades ;
}

void FabricaBonus::destroy(){
	delete FabricaBonus::singleton ;
	FabricaBonus::instance = false;
}


void FabricaBonus::cargarSorteo(){
	// CREO EL SORTEO CON LAS PROBABILIDADES
	// Si lo creo en el constructor se crea siempre con los valores por defecto
	this->sorteo = new Sorteo();
	
	IteradorLista<PropiedadesFabricaBonus>* it = new IteradorLista<PropiedadesFabricaBonus>(this->listaPropiedades);
	while(it->tieneSiguiente()){
		PropiedadesFabricaBonus* prop = it->siguiente();
		std::stringstream ss ;
		ss << "SORTEO: " << prop->getId() << " - PROB: "<< prop->getProbabilidad() ;
		Logger::getInstance()->debug(ss.str());
		this->sorteo->agregarElemento(prop->getId(),prop->getProbabilidad());
	}
}

PersonajeBonus* FabricaBonus::getProximoBonus(Punto* medio){
	
	if(!this->sorteoCargado){
		this->sorteoCargado = true ;
		this->cargarSorteo();
	}

	PersonajeBonus* pb = 0 ;
	//Punto* medio = EscenarioModelo::getEscenario()->getPuntoMedioDelBonus();
	if(medio){
		int radio = EscenarioModelo::getEscenario()->getRadioStandard();
		Punto* puntoBonus = EscenarioModelo::getEscenario()->getSendero()->getPuntoSenderoConPuntoGrilla(medio->getX(),medio->getY());	
		std::stringstream ss ;
		string* bolilla = this->sorteo->getElementoSorteado() ;
		if(bolilla){
			
			ss << "Random para calculo de bonus: " << *bolilla ;
			
			if(bolilla->compare(FabricaBonus::ID_CAMBIO_PRESA) == 0){
				pb = this->getBonusCambioDePresa();
			}else if(bolilla->compare(FabricaBonus::ID_CONGELAR) == 0){
				pb = this->getBonusCongelar();
			}else if(bolilla->compare(FabricaBonus::ID_DUPLICA) == 0){
				pb = this->getBonusDuplicaMisPuntosAcumulados();
			}else if(bolilla->compare(FabricaBonus::ID_LENTO) == 0){
				pb = this->getBonusReducirVelocidadOponente();
			}else if(bolilla->compare(FabricaBonus::ID_PTO_OPONENTE) == 0){
				pb = this->getBonusAdquirirPuntosDelOponente();
			}else if(bolilla->compare(FabricaBonus::ID_RAPIDO) == 0){
				pb = this->getBonusDuplicarVelocidad();
			}
		}else{
			ss << "No salio ninguna bolilla, falta completar el 100% de probabilidades." ;
		}
		Logger::getInstance()->debug(ss.str());
		if(pb){
			pb->getObjeto()->setPosicion(puntoBonus,true);
			pb->getObjeto()->setRadio(radio);
		}

		//delete medio ;
	}
	return pb ;

}


